package com.evaluationSystem.controller;

import cn.hutool.core.util.RandomUtil;
import com.evaluationSystem.config.PropertiesConfig;
import com.evaluationSystem.config.R;
import com.evaluationSystem.config.RCode;
import com.evaluationSystem.entity.SecurityUser;
import com.evaluationSystem.entity.SysLogLoginEntity;
import com.evaluationSystem.entity.UserDetail;
import com.evaluationSystem.entity.dto.LoginDTO;
import com.evaluationSystem.entity.dto.SysUserDTO;
import com.evaluationSystem.enums.LoginOperationEnum;
import com.evaluationSystem.enums.LoginStatusEnum;
import com.evaluationSystem.enums.UserStatusEnum;
import com.evaluationSystem.exception.EvaluationException;
import com.evaluationSystem.password.PasswordUtils;
import com.evaluationSystem.service.SysLogLoginService;
import com.evaluationSystem.service.SysUserService;
import com.evaluationSystem.service.SysUserTokenService;
import com.evaluationSystem.util.*;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Map;


@RestController
@RequestMapping("/sys")
@Slf4j
public class LoginController {
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysLogLoginService sysLogLoginService;
    @Autowired
    private PropertiesConfig propertiesConfig;
    @Autowired
    private LogOperationService logOperationService;
    @Autowired
    private SysUserTokenService sysUserTokenService;

    private final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
    /**
     * 签名密钥串(字典等敏感接口)
     */
    private String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a";

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public R<Map> login(@RequestBody LoginDTO login, HttpServletRequest request) {

        String captcha = login.getCaptcha();
        if (captcha == null) {
            return R.failed("验证码无效");
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        String origin = lowerCaseCaptcha + login.getCheckKey() + signatureSecret;
        String realKey = Md5Util.md5Encode(origin, "utf-8");
        Object checkCode = redisUtil.get(realKey);
        //当进入登录页时，有一定几率出现验证码错误
        if (checkCode == null || !checkCode.toString().equals(lowerCaseCaptcha)) {
            log.warn("验证码错误，key= {} , Ui checkCode= {}, Redis checkCode = {}", login.getCheckKey(), lowerCaseCaptcha, checkCode);
            // 改成特殊的code 便于前端判断
            return R.failed(RCode.PARAM_VALIDATION_FAILURE, "验证码错误", null);
        }
        //用户信息
        SysUserDTO user = sysUserService.getByUsername(login.getUsername());

        SysLogLoginEntity log = new SysLogLoginEntity();
        log.setOperation(LoginOperationEnum.LOGIN.value());
        log.setCreateDate(new Date());
        log.setIp(IpUtils.getIpAddr(request));
        log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        log.setIp(IpUtils.getIpAddr(request));

        //用户不存在
        if(user == null){
            log.setStatus(LoginStatusEnum.FAIL.value());
            log.setCreatorName(login.getUsername());
            sysLogLoginService.save(log);

            throw new EvaluationException("账号不存在");
        }

        //密码错误
        if(!PasswordUtils.matches(login.getPassword(), user.getPassword())){
            log.setStatus(LoginStatusEnum.FAIL.value());
            log.setCreator(user.getId());
            log.setCreatorName(user.getUsername());
            sysLogLoginService.save(log);

            throw new EvaluationException("账号或密码错误");
        }

        //账号停用
        if(user.getStatus() == UserStatusEnum.DISABLE.value()){
            log.setStatus(LoginStatusEnum.LOCK.value());
            log.setCreator(user.getId());
            log.setCreatorName(user.getUsername());
            sysLogLoginService.save(log);

            throw new EvaluationException("账号已被停用");
        }

        //登录成功
        log.setStatus(LoginStatusEnum.SUCCESS.value());
        log.setCreator(user.getId());
        log.setCreatorName(user.getUsername());
        sysLogLoginService.save(log);

        // 调用接口添加访问记录
        if (!"dev".equals(propertiesConfig.getEnv())) {
            LogOperationParams logOperationParams = new LogOperationParams();
            logOperationParams.setOperateId(request.getRequestURI());
            logOperationParams.setOperateType("1");
            logOperationParams.setOperateName("pc端账号密码登录");
            logOperationParams.setButtonType("goto");
            logOperationParams.setStaffName(user.getUsername());
            logOperationService.saveLog(logOperationParams);
        }

        return sysUserTokenService.createToken(user);
//        Subject subject = SecurityUtils.getSubject();
//        try {
//            subject.login(new UsernamePasswordToken(user.getUserId(), user.getUserPassword()));
//            User loginUser = (User) subject.getPrincipal();
//            UserVo userVo = new UserVo();
//            BeanUtils.copyProperties(loginUser, userVo);
//            userVo.setQuestionList(loginUser.getQuestionList().contains(",") ? List.of(loginUser.getQuestionList().split(",")) : List.of(loginUser.getQuestionList()));
//            request.getSession().setAttribute("user", userVo);
//            return R.success(userVo);
//        } catch (UnknownAccountException e) {
//            e.printStackTrace();
//            return R.failed(RCode.LOGIN_FAIL, "用户名不存在");
//        } catch (IncorrectCredentialsException e) {
//            e.printStackTrace();
//            return R.failed(RCode.LOGIN_FAIL, "密码错误");
//        }
    }

    @PostMapping("logout")
    public R<String> logout(HttpServletRequest request) {
        UserDetail user = SecurityUser.getUser();

        //退出
        sysUserTokenService.logout(user.getId());

        //用户信息
        SysLogLoginEntity log = new SysLogLoginEntity();
        log.setOperation(LoginOperationEnum.LOGOUT.value());
        log.setIp(IpUtils.getIpAddr(request));
        log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        log.setIp(IpUtils.getIpAddr(request));
        log.setStatus(LoginStatusEnum.SUCCESS.value());
        log.setCreator(user.getId());
        log.setCreatorName(user.getUsername());
        log.setCreateDate(new Date());
        sysLogLoginService.save(log);

        return R.success("登出成功");
    }

    /**
     * 后台生成图形验证码 ：有效
     *
     * @param response
     * @param key
     */
    @ApiOperation("获取验证码")
    @GetMapping(value = "/randomImage/{key}")
    public R<String> randomImage(HttpServletResponse response, @PathVariable("key") String key) {
        try {
            //生成验证码
            String code = RandomUtil.randomString(BASE_CHECK_CODES, 4);
            //存到redis中
            String lowerCaseCode = code.toLowerCase();

            //update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
            // 加入密钥作为混淆，避免简单的拼接，被外部利用，用户自定义该密钥即可
            String origin = lowerCaseCode + key + signatureSecret;
            String realKey = Md5Util.md5Encode(origin, "utf-8");
            //update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906

            redisUtil.set(realKey, lowerCaseCode, 60);
            log.info("获取验证码，Redis key = {}，checkCode = {}", realKey, code);
            //返回前端
            String base64 = RandImageUtil.generate(code);
            return R.success(base64);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return R.failed("获取验证码失败,请检查redis配置!");
        }
    }

}
